/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GUI.EditPanes.Spatial;

import GUI.Components.BButton;
import GUI.Components.BTextField;
import GUI.Components.Float3Panel;
import GUI.EditPanes.EditTaskPane;
import General.CurrentData;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.ConeCollisionShape;
import com.jme3.bullet.collision.shapes.CylinderCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.concurrent.Callable;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import se.datadosen.component.RiverLayout;

/**
 *
 * @author David
 */
public class PhysicsTaskPane extends EditTaskPane
{

    private JCheckBox enablePhysicsCheckBox = new JCheckBox("", false);
    private BTextField massField = new BTextField("Float");
    private BTextField restitutionField = new BTextField("Float");
    private JCheckBox kinematicCheckBox = new JCheckBox("", false);
    private JComboBox<String> collisionShapeComboBox = new JComboBox<String>(new String[]
    {
        "Box", "Capsule", "Cone", "Cylinder", "Dynamic Mesh", "Static Mesh"
    });
    private Spatial spatial;
    private JPanel currentCShapePanel = new JPanel();
    private CShape_BoxPanel cShape_BoxPanel;
    private CShape_CapsulePanel cShape_CapsulePanel;
    private CShape_ConePanel cShape_ConePanel;
    private CShape_CylinderPanel cShape_CylinderPanel;
    private BButton syncTransformButton = new BButton("Sync Transform");
    private BButton clearForcesButton = new BButton("Clear Forces");

    /**
     *
     */
    public PhysicsTaskPane()
    {
        spatial = (Spatial) CurrentData.getEditorWindow().getB3DApplication().getSelectedObject();
        enablePhysicsCheckBox.setSelected(spatial.getControl(RigidBodyControl.class) != null);
        clearForcesButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                RigidBodyControl rbc = new RigidBodyControl();
                if (CurrentData.getEditorWindow().getB3DApplication().isPhysicsPlaying())
                {
                    CurrentData.getEditorWindow().getB3DApplication().getBulletAppState().getPhysicsSpace().remove(spatial.getControl(RigidBodyControl.class));
                }
                spatial.removeControl(spatial.getControl(RigidBodyControl.class));
                spatial.addControl(rbc);
                if (CurrentData.getEditorWindow().getB3DApplication().isPhysicsPlaying())
                {
                    CurrentData.getEditorWindow().getB3DApplication().getBulletAppState().getPhysicsSpace().add(spatial.getControl(RigidBodyControl.class));
                }
                updateRigidBodyControl();
            }
        });
        syncTransformButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                {
                    public Void call() throws Exception
                    {
                        spatial.getControl(RigidBodyControl.class).setPhysicsLocation(spatial.getWorldTranslation());
                        spatial.getControl(RigidBodyControl.class).setPhysicsRotation(spatial.getWorldRotation());
                        return null;
                    }
                });
            }
        });
        collisionShapeComboBox.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent e)
            {
                switch (collisionShapeComboBox.getSelectedIndex())
                {
                    case 0:
                        massField.setEnabled(true);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(new BoxCollisionShape(new Vector3f(1, 1, 1)));
                        break;
                    case 1:
                        massField.setEnabled(true);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(new CapsuleCollisionShape(1, 1.5f));
                        break;
                    case 2:
                        massField.setEnabled(true);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(new ConeCollisionShape(1, 1.5f));
                        break;
                    case 3:
                        massField.setEnabled(true);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(new CylinderCollisionShape(new Vector3f(1, 1, 1)));
                        break;
                    case 4:
                        massField.setEnabled(true);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(CollisionShapeFactory.createDynamicMeshShape(spatial));
                        spatial.setUserData("cShape", "dynamic");
                        break;
                    case 5:
                        massField.setText("0");
                        massField.setEnabled(false);
                        spatial.getControl(RigidBodyControl.class).setMass(0);
                        spatial.getControl(RigidBodyControl.class).setCollisionShape(CollisionShapeFactory.createMeshShape(spatial));
                        spatial.setUserData("cShape", "static");
                        break;
                }
                arrangeCShapePanel();
            }
        });
        enablePhysicsCheckBox.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent e)
            {
                CurrentData.getEditorWindow().getB3DApplication().enqueue(new Callable<Void>()
                {
                    public Void call() throws Exception
                    {
                        if (enablePhysicsCheckBox.isSelected())
                        {
                            spatial.addControl(new RigidBodyControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 3));
                            spatial.getControl(RigidBodyControl.class).setRestitution(1);
                            spatial.setUserData("cShape", "");
                        } else
                        {
                            CurrentData.getEditorWindow().getB3DApplication().getBulletAppState().getPhysicsSpace().remove(spatial.getControl(RigidBodyControl.class));
                            spatial.removeControl(RigidBodyControl.class);
                        }
                        arrange();
                        return null;
                    }
                });
            }
        });
        applyButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                updateRigidBodyControl();
            }
        });
        taskPane.setTitle("Physics Properties");
        taskPane.setLayout(new RiverLayout(10, 0));
        add(taskPane, BorderLayout.CENTER);
        taskPane.add("left", new JLabel("Enable"));
        taskPane.add("tab hfill", enablePhysicsCheckBox);
        arrange();
    }

    private void arrange()
    {
        taskPane.removeAll();
        taskPane.add("left", new JLabel("Enable"));
        taskPane.add("tab hfill", enablePhysicsCheckBox);
        if (spatial.getControl(RigidBodyControl.class) != null)
        {
            if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof CapsuleCollisionShape)
            {
                collisionShapeComboBox.setSelectedIndex(1);
            } else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof ConeCollisionShape)
            {
                collisionShapeComboBox.setSelectedIndex(2);
            } else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof CylinderCollisionShape)
            {
                collisionShapeComboBox.setSelectedIndex(3);
            } else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof BoxCollisionShape)
            {
                collisionShapeComboBox.setSelectedIndex(0);
            } else if (spatial.getUserData("cShape").equals("dynamic"))
            {
                collisionShapeComboBox.setSelectedIndex(4);
            } else if (spatial.getUserData("cShape").equals("static"))
            {
                collisionShapeComboBox.setSelectedIndex(5);
            }
            kinematicCheckBox.setSelected(spatial.getControl(RigidBodyControl.class).isKinematic());
            taskPane.add("br left", new JLabel("Mass:"));
            taskPane.add("tab hfill", massField);
            taskPane.add("br left", new JLabel("Restitution:"));
            taskPane.add("tab hfill", restitutionField);
            taskPane.add("br left", new JLabel("Kincematic:"));
            taskPane.add("tab hfill", kinematicCheckBox);
            taskPane.add("br left", new JLabel("Collision Shape:"));
            taskPane.add("tab hfill", collisionShapeComboBox);
            massField.setText("" + spatial.getControl(RigidBodyControl.class).getMass());
            restitutionField.setText("" + spatial.getControl(RigidBodyControl.class).getRestitution());
            arrangeCShapePanel();
            taskPane.add("br", clearForcesButton);
            taskPane.add(syncTransformButton);
            taskPane.add(applyButton);
        }
    }

    private void updateRigidBodyControl()
    {
        CollisionShape collisionShape = null;
        if (collisionShapeComboBox.getSelectedIndex() == 4)
        {
            collisionShape = CollisionShapeFactory.createDynamicMeshShape(spatial);
        } else if (collisionShapeComboBox.getSelectedIndex() == 5)
        {
            collisionShape = CollisionShapeFactory.createMeshShape(spatial);
        } else if (currentCShapePanel instanceof CShape_BoxPanel)
        {
            CShape_BoxPanel cShape_BoxPanel = (CShape_BoxPanel) currentCShapePanel;
            collisionShape = new BoxCollisionShape(cShape_BoxPanel.getHalfExtents());
        } else if (currentCShapePanel instanceof CShape_CapsulePanel)
        {
            CShape_CapsulePanel cShape_CapsulePanel = (CShape_CapsulePanel) currentCShapePanel;
            collisionShape = new CapsuleCollisionShape(cShape_CapsulePanel.getRadius(), cShape_CapsulePanel.getShapeHeight());
        } else if (currentCShapePanel instanceof CShape_ConePanel)
        {
            CShape_ConePanel cShape_ConePanel = (CShape_ConePanel) currentCShapePanel;
            collisionShape = new ConeCollisionShape(cShape_ConePanel.getRadius(), cShape_ConePanel.getShapeHeight());
        } else if (currentCShapePanel instanceof CShape_CylinderPanel)
        {
            CShape_CylinderPanel cShape_CylinderPanel = (CShape_CylinderPanel) currentCShapePanel;
            collisionShape = new CylinderCollisionShape(cShape_CylinderPanel.getHalfExtents());
        }
        spatial.getControl(RigidBodyControl.class).setKinematic(kinematicCheckBox.isSelected());
        spatial.getControl(RigidBodyControl.class).setMass(Float.parseFloat(massField.getText()));
        spatial.getControl(RigidBodyControl.class).setRestitution(Float.parseFloat(restitutionField.getText()));
        spatial.getControl(RigidBodyControl.class).setCollisionShape(collisionShape);
    }

    private void arrangeCShapePanel()
    {
        if (currentCShapePanel != null)
        {
            taskPane.remove(currentCShapePanel);
        }
        taskPane.remove(syncTransformButton);
        taskPane.remove(clearForcesButton);
        taskPane.remove(applyButton);
        if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof CapsuleCollisionShape)
        {
            cShape_CapsulePanel = new CShape_CapsulePanel((CapsuleCollisionShape) spatial.getControl(RigidBodyControl.class).getCollisionShape());
            currentCShapePanel = cShape_CapsulePanel;
            taskPane.add("br hfill", currentCShapePanel);
        } else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof ConeCollisionShape)
        {
            cShape_ConePanel = new CShape_ConePanel((ConeCollisionShape) spatial.getControl(RigidBodyControl.class).getCollisionShape());
            currentCShapePanel = cShape_ConePanel;
            taskPane.add("br hfill", currentCShapePanel);
        } else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof CylinderCollisionShape)
        {
            cShape_CylinderPanel = new CShape_CylinderPanel((CylinderCollisionShape) spatial.getControl(RigidBodyControl.class).getCollisionShape());
            currentCShapePanel = cShape_CylinderPanel;
            currentCShapePanel.setBorder(new BevelBorder(BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
            taskPane.add("br hfill", currentCShapePanel);
        }/* else if (spatial.getUserData("cShape").equals("dynamic")) {
         collisionShapeComboBox.setSelectedIndex(4);
         } else if (spatial.getUserData("cShape").equals("static")) {
         collisionShapeComboBox.setSelectedIndex(5);
         }*/ else if (spatial.getControl(RigidBodyControl.class).getCollisionShape() instanceof BoxCollisionShape)
        {
            cShape_BoxPanel = new CShape_BoxPanel((BoxCollisionShape) spatial.getControl(RigidBodyControl.class).getCollisionShape());
            currentCShapePanel = cShape_BoxPanel;
            taskPane.add("br hfill", currentCShapePanel);
        }
        taskPane.add("br", clearForcesButton);
        taskPane.add(syncTransformButton);
        taskPane.add(applyButton);
    }

    class CShape_BoxPanel extends JPanel
    {

        private Float3Panel halfExtendsPanel;

        public CShape_BoxPanel(BoxCollisionShape bcs)
        {
            setBorder(new BevelBorder(BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
            halfExtendsPanel = new Float3Panel(bcs.getHalfExtents());
            setLayout(new RiverLayout(10, 5));
            add("left", new JLabel("Half Extends:"));
            add("tab hfill", halfExtendsPanel);
        }

        Vector3f getHalfExtents()
        {
            return halfExtendsPanel.getVector();
        }
    }

    class CShape_CapsulePanel extends JPanel
    {

        private BTextField radiusField = new BTextField("float");
        private BTextField heightTextField = new BTextField("float");

        public CShape_CapsulePanel(CapsuleCollisionShape ccs)
        {
            setBorder(new BevelBorder(BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
            taskPane.remove(currentCShapePanel);
            radiusField.setText("" + ccs.getRadius());
            heightTextField.setText("" + ccs.getHeight());
            setLayout(new RiverLayout(10, 5));
            add("left", new JLabel("Height:"));
            add("tab hfill", heightTextField);
            add("br left", new JLabel("Radius:"));
            add("tab hfill", radiusField);
        }

        float getRadius()
        {
            return Float.parseFloat(radiusField.getText());
        }

        float getShapeHeight()
        {
            return Float.parseFloat(heightTextField.getText());
        }
    }

    class CShape_ConePanel extends JPanel
    {

        private BTextField radiusField = new BTextField("float");
        private BTextField heightTextField = new BTextField("float");

        public CShape_ConePanel(ConeCollisionShape ccs)
        {
            setBorder(new BevelBorder(BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
            radiusField.setText("" + ccs.getRadius());
            heightTextField.setText("" + ccs.getHeight());
            setLayout(new RiverLayout(10, 5));
            add("left", new JLabel("Height:"));
            add("tab hfill", heightTextField);
            add("br left", new JLabel("Radius:"));
            add("tab hfill", radiusField);
        }

        float getRadius()
        {
            return Float.parseFloat(radiusField.getText());
        }

        float getShapeHeight()
        {
            return Float.parseFloat(heightTextField.getText());
        }
    }

    class CShape_CylinderPanel extends JPanel
    {

        private Float3Panel halfExtendsPanel;

        public CShape_CylinderPanel(CylinderCollisionShape ccs)
        {
            setBorder(new BevelBorder(BevelBorder.LOWERED, Color.lightGray, Color.darkGray));
            halfExtendsPanel = new Float3Panel(ccs.getHalfExtents());
            halfExtendsPanel.getyField().setEnabled(false);
            setLayout(new RiverLayout(10, 5));
            add("left", new JLabel("Half Extends:"));
            add("tab hfill", halfExtendsPanel);
        }

        Vector3f getHalfExtents()
        {
            return halfExtendsPanel.getVector();
        }
    }
}
